/*
 * Copyright (C) 2013 Buptcoder
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.buptcoder.wifimap.location;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.buptcoder.wifimap.Utils.MapLog;
import com.buptcoder.wifimap.Utils.Utils;

import android.content.Context;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

public class Locator {

    private static final String TAG = "onProviderDisabled";

    private static Locator mInstance;
    private Context mContext;
    private LocationManager mLocationManager;
    private Location mLocation;
    private double mLatitude;
    private double mLongitude;
    private final List<OnLocationChangedListener> mListeners;
    private boolean hasGetLocation;

    private final LocationListener mLocationListener;
    private Object lock;

    public synchronized static Locator getInstance(Context context) {
        if (mInstance == null) {
            mInstance = new Locator(context);
        }
        return mInstance;
    }

    public boolean isInValid() {
        return hasGetLocation;
    }

    private Locator(Context context) {
        mContext = context;
        mLocationListener = new WifiLocationListener();
        mLatitude = Utils.getLastLatitude(context);
        mLongitude = Utils.getLastLongitude(context);
        lock = new Object();
        mListeners = Collections
                .synchronizedList(new ArrayList<OnLocationChangedListener>());
        configureGPSDevice();
        updateWithNewLocation(mLocation);
    }

    private void configureGPSDevice() {
        mLocationManager = (LocationManager) mContext
                .getSystemService(Context.LOCATION_SERVICE);
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        criteria.setAltitudeRequired(false);
        criteria.setBearingRequired(false);
        criteria.setCostAllowed(true);
        criteria.setPowerRequirement(Criteria.POWER_LOW);
        String provider = mLocationManager.getBestProvider(criteria, true);
        if (provider == null) {
            hasGetLocation = true;
            return;
        }

        mLocation = mLocationManager.getLastKnownLocation(provider);
        mLocationManager.requestLocationUpdates(provider, 2000, 10,
                mLocationListener);
    }

    private void updateWithNewLocation(Location location) {
        if (location != null) {
            mLatitude = location.getLatitude();
            mLongitude = location.getLongitude();
            Utils.setLastLatitdue(mContext, mLatitude);
            Utils.setLastLongitude(mContext, mLongitude);
        }
    }

    public double getLatitude() {
        return mLatitude;
    }

    public double getLongitude() {
        return mLongitude;
    }

    public void addLocationChangeListener(OnLocationChangedListener listener) {
        synchronized (lock) {
            mListeners.add(listener);
        }
    }

    public void removeLocationChangeListener(OnLocationChangedListener listener) {
        synchronized (lock) {
            if (mListeners != null && mListeners.size() > 0) {
                mListeners.remove(listener);
            }
        }
    }

    public interface OnLocationChangedListener {
        public void onLocationChanged();
    }

    private class WifiLocationListener implements LocationListener {
        public synchronized void onLocationChanged(Location location) {
            updateWithNewLocation(location);
            synchronized (lock) {
                nofityChanged();
            }
        }

        private void nofityChanged() {
            if (mListeners != null && mListeners.size() > 0) {
                for (OnLocationChangedListener listener : mListeners) {
                    listener.onLocationChanged();
                }
            }
        }

        public void onProviderDisabled(String provider) {
            MapLog.d(TAG, "onProviderDisabled");
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    }
}
